#if UNITY_EDITOR
using UnityEngine;
using UnityEngine.UIElements;

namespace GameDesigner
{

    internal class ZoomManipulator : MouseManipulator
    {
        private VisualElement m_GraphUI;
        private bool m_Active;
        private Vector2 m_Start;
        private Vector2 m_Last;
        private Vector2 m_ZoomCenter;
        public float zoomStep { get; set; }

        public ZoomManipulator(VisualElement graphUI)
        {
            m_GraphUI = graphUI;
            zoomStep = 0.05f;
            activators.Add(new ManipulatorActivationFilter
            {
                button = MouseButton.RightMouse,
                modifiers = EventModifiers.Alt
            });
        }

        protected override void RegisterCallbacksOnTarget()
        {
            target.RegisterCallback<WheelEvent>(OnScroll, TrickleDown.TrickleDown);
            target.RegisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown);
            target.RegisterCallback<MouseMoveEvent>(OnMouseMove, TrickleDown.TrickleDown);
            target.RegisterCallback<MouseUpEvent>(OnMouseUp, TrickleDown.TrickleDown);
        }

        protected override void UnregisterCallbacksFromTarget()
        {
            target.UnregisterCallback<WheelEvent>(OnScroll, TrickleDown.TrickleDown);
            target.UnregisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown);
            target.UnregisterCallback<MouseMoveEvent>(OnMouseMove, TrickleDown.TrickleDown);
            target.UnregisterCallback<MouseUpEvent>(OnMouseUp, TrickleDown.TrickleDown);
        }

        private void OnScroll(WheelEvent e)
        {
            Vector2 zoomCenter = target.ChangeCoordinatesTo(m_GraphUI, e.localMousePosition);
            float zoomScale = 1f - e.delta.y * zoomStep;
            Zoom(zoomCenter, zoomScale);
            e.StopPropagation();
        }

        protected void OnMouseDown(MouseDownEvent e)
        {
            if (CanStartManipulation(e))
            {
                m_Start = m_Last = e.localMousePosition;
                m_ZoomCenter = target.ChangeCoordinatesTo(m_GraphUI, m_Start);
                m_Active = true;
                target.CaptureMouse();
                e.StopPropagation();
            }
        }

        protected void OnMouseMove(MouseMoveEvent e)
        {
            if (m_Active)
            {
                Vector2 vector = e.localMousePosition - m_Last;
                float zoomScale = 1f + ((vector.x + vector.y) * zoomStep);
                Zoom(m_ZoomCenter, zoomScale);
                e.StopPropagation();
                m_Last = e.localMousePosition;
            }
        }

        protected void OnMouseUp(MouseUpEvent e)
        {
            if (m_Active && CanStopManipulation(e))
            {
                m_Active = false;
                target.ReleaseMouse();
                e.StopPropagation();
            }
        }

        private void Zoom(Vector2 zoomCenter, float zoomScale)
        {
            Vector3 position = m_GraphUI.transform.position;
            Vector3 scale = m_GraphUI.transform.scale;
            Vector2 min = m_GraphUI.layout.min;
            float x = zoomCenter.x + min.x;
            float y = zoomCenter.y + min.y;
            position += Vector3.Scale(new Vector3(x, y, 0f), scale);
            scale = Vector3.Scale(scale, new Vector3(zoomScale, zoomScale, 1f));
            scale.x = Mathf.Clamp(scale.x, 0.1f, 1.5f);
            scale.y = Mathf.Clamp(scale.y, 0.1f, 1.5f);
            position -= Vector3.Scale(new Vector3(x, y, 0f), scale);
            m_GraphUI.transform.position = position;
            m_GraphUI.transform.scale = scale;
        }
    }
}
#endif